package org.jeecg.common.util;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
import java.util.stream.Stream;

/**
 * 结果跑龙套
 *
 * @author Yafei Song
 * @date 2022/09/14
 */
@Data
public class Result<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 成功标志
     */
    @ApiModelProperty(value = "成功标志")
    private boolean success = true;

    /**
     * 返回处理消息
     */
    @ApiModelProperty(value = "返回处理消息")
    private String message = "";

    /**
     * 返回代码
     */
    @ApiModelProperty(value = "返回代码")
    private Integer code = 0;

    /**
     * 返回数据对象 data
     */
    @ApiModelProperty(value = "返回数据对象")
    private T result;

    /**
     * 时间戳
     */
    @ApiModelProperty(value = "时间戳")
    private long timestamp = System.currentTimeMillis();

    public Result() {
    }

    /**
     * 兼容VUE3版token失效不跳转登录页面
     *
     * @param code
     * @param message
     */
    public Result(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Result(T value) {
        this.result = Objects.requireNonNull(value);
    }

    public Result(String msg, T value) {
        this.message = msg;
        this.result = Objects.requireNonNull(value);
    }

    public Result<T> success(String message) {
        this.message = message;
        this.code = 200;
        this.success = true;
        return this;
    }


    public static <T> Result<T> ok() {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        return r;
    }


    public static <T> Result<T> ok(String msg) {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        r.setMessage(msg);
        return r;
    }


    public static <T> Result<T> ok(T data) {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        r.setResult(data);
        return r;
    }

    public static <T> Result<T> OK() {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        return r;
    }


    public static <T> Result<T> OK(T data) {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        r.setResult(data);
        return r;
    }

    public static <T> Result<T> OK(String msg, T data) {
        Result<T> r = new Result<T>();
        r.setSuccess(true);
        r.setCode(200);
        r.setMessage(msg);
        r.setResult(data);
        return r;
    }

    public static <T> Result<T> error(String msg, T data) {
        Result<T> r = new Result<T>();
        r.setSuccess(false);
        r.setCode(500);
        r.setMessage(msg);
        r.setResult(data);
        return r;
    }

    public static <T> Result<T> error(String msg) {
        return error(500, msg);
    }

    public static <T> Result<T> error(int code, String msg) {
        Result<T> r = new Result<T>();
        r.setCode(code);
        r.setMessage(msg);
        r.setSuccess(false);
        return r;
    }

    public Result<T> error500(String message) {
        this.message = message;
        this.code = 500;
        this.success = false;
        return this;
    }


    @JsonIgnore
    private String onlTable;

    public static Result<Object> status(boolean flag) {
        return flag ? OK().success("操作成功") : error("操作失败");
    }


    /**
     * 空对象
     *
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> empty() {
        @SuppressWarnings("unchecked")
        Result<T> t = new Result();
        return t;
    }

    /**
     * 空对象
     *
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> errorEmpty(String message) {
        return Result.error(message);
    }


    /**
     * 空对象
     *
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> empty(String message) {
        return Result.ok(message);
    }


    /**
     * <h1>Result of 方法</h1>
     * 设置Result
     *
     * @param value 价值
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> of(T value) {
        return new Result<T>(value);
    }

    /**
     * <h1>Result of 方法</h1>
     * 设置Result
     *
     * @param value 价值
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> errorOf(int code, String value) {
        return Result.error(code, value);
    }


    /**
     * <h1>Result ofNullable 可null方法</h1>
     * 可空
     *
     * @param value 价值
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }


    /**
     * <h1>Result ofNullable 可null方法</h1>
     * 可空
     *
     * @param value 价值
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> ofNullable(String mes, T value) {
        return value == null ? Result.empty(mes) : Result.ok(value);
    }


    /**
     * 误差可以为空
     * <h1>Result ofNullable 可null方法</h1>
     * 可空
     *
     * @param code  代码
     * @param mes   市场经济地位
     * @param value 价值
     * @return {@link Result}<{@link T}>
     */
    public static <T> Result<T> errorOfNullable(int code, String mes, T value) {
        return value == null ? Result.errorEmpty(mes) : Result.errorOf(code, mes);
    }


    /**
     * 得到
     *
     * @return {@link T}
     */
    public T getData() {
        if (result == null) {
            throw new NoSuchElementException("No value present");
        }
        return result;
    }

    /**
     * 得到
     *
     * @return {@link T}
     */
    public Result<T> get() {
        if (result == null) {
            throw new NoSuchElementException("No value present");
        }
        return this;
    }

    /**
     * <h1>存在则进行处理</h1>
     * 存在
     *
     * @param consumer 消费者
     */
    public void isPresent(Consumer<? super T> consumer) {
        if (result != null) {
            consumer.accept(result);
        }
    }


    /**
     * <h1>过滤</h1>
     * 返回过滤后的数据
     *
     * @param predicate 谓词
     * @return {@link Result}<{@link T}>
     */
    public Result<T> filter(@NotNull Predicate<? super T> predicate) {
        if (!isPresent()) {
            return this;
        } else {
            return predicate.test(result) ? this : empty();
        }
    }

    /**
     * <h1>代表了一个接受两个输入参数的操作，并且不返回任何结果<h1/>
     * BiConsumer
     * 代表了一个接受两个输入参数的操作，并且不返回任何结果
     *
     * @param value      价值
     * @param biConsumer bi消费者
     */
    public void body(T value, @NotNull BiConsumer<T, ? super T> biConsumer) {
        biConsumer.accept(result, value);
    }


    /**
     * <h1>代表了一个接受两个输入参数的方法，并且返回一个结果<h1/>
     * BiFunction<T,U,R>
     * 代表了一个接受两个输入参数的方法，并且返回一个结果
     *
     * @param t1         t1
     * @param biFunction bi功能
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T t1,T t2, @NotNull BiFunction<T, ? super T, ? super T> biFunction) {
        Objects.requireNonNull(t1, "result is null");
        T apply = (T) biFunction.apply(t1, t2);
        this.setResult(apply);
        return this;
    }

    /**
     * <h1>代表了一个作用于于两个同类型操作符的操作，并且返回了操作符同类型的结果<h1/>
     * BinaryOperator<T>
     * 代表了一个作用于于两个同类型操作符的操作，并且返回了操作符同类型的结果
     *
     * @param value          价值
     * @param binaryOperator 二元运算符
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T value, @NotNull BinaryOperator<T> binaryOperator) {
        Objects.requireNonNull(value, "value is null");
        this.setResult(binaryOperator.apply(result, value));
        return this;
    }

    /**
     * <h1>代表了一个两个参数的boolean值方法<h1/>
     * BiPredicate<T,U>
     * 代表了一个两个参数的boolean值方法
     *
     * @param value       价值
     * @param biPredicate bi谓词
     * @return {@link Result}<{@link T}>
     */
    public Result<T> bodyBoolean(T value, @NotNull BiPredicate<T, ? super T> biPredicate) {
        Objects.requireNonNull(value, "value is null");
        biPredicate.test(result, value);
        return this;
    }

    /**
     * <h1>代表了boolean值结果的提供方</h1>
     * BooleanSupplier
     * 代表了boolean值结果的提供方
     *
     * @param booleanSupplier 布尔供应商
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(@NotNull BooleanSupplier booleanSupplier) {
        Objects.requireNonNull(result, "value is null");
        booleanSupplier.getAsBoolean();
        return this;
    }

    /**
     * <h1>代表了接受一个输入参数并且无返回的操作</h1>
     * Consumer<T>
     * 代表了接受一个输入参数并且无返回的操作
     *
     * @param consumer 消费者
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T value, @NotNull Consumer<T> consumer) {
        Objects.requireNonNull(value, "value is null");
        consumer.accept(value);
        return this;
    }


    /**
     * <h1>接受一个输入参数，返回一个结果</h1>
     * Function<T,R>
     * 接受一个输入参数，返回一个结果。
     *
     * @param value    价值
     * @param function 函数
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T value, @NotNull Function<T, ? super T> function) {
        Objects.requireNonNull(value, "value is null");
        this.setResult((T) function.apply(value));
        return this;
    }


    /**
     * <h1>无参数，返回一个int类型结果。</h1>
     * IntSupplier
     * 无参数，返回一个int类型结果。
     *
     * @param intSupplier int供应商
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(@NotNull IntSupplier intSupplier) {
        intSupplier.getAsInt();
        return this;
    }

    /**
     * <h1>无参数，返回一个结果/h1>
     * Supplier<T>
     * 无参数，返回一个结果。
     *
     * @param supplier 供应商
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(@NotNull Supplier<T> supplier) {
        this.setResult(supplier.get());
        return this;
    }

    /**
     * <h1> 接受一个输入参数，返回一个布尔值结果</h1>
     * Predicate<T>
     * 接受一个输入参数，返回一个布尔值结果。
     *
     * @param value     价值
     * @param predicate 谓词
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T value, @NotNull Predicate<T> predicate) {
        Objects.requireNonNull(value, "value is null");
        predicate.test(value);
        return this;
    }

    /**
     * <h1>接受一个参数为类型T,返回值类型也为T</h1>
     * UnaryOperator<T>
     * 接受一个参数为类型T,返回值类型也为T。
     *
     * @param value         价值
     * @param unaryOperator 一元运算符
     * @return {@link Result}<{@link T}>
     */
    public Result<T> body(T value, @NotNull UnaryOperator<T> unaryOperator) {
        Objects.requireNonNull(value, "value is null");
        this.setResult(unaryOperator.apply(value));
        return this;
    }

    /**
     * 流
     *
     * @return {@link Stream}<{@link T}>
     */
    public Stream<T> stream() {
        if (!isPresent()) {
            return Stream.empty();
        } else {
            return Stream.of(result);
        }
    }

    /**
     * If a value is present, returns the value, otherwise returns
     * {@code other}.
     *
     * @param other the value to be returned, if no value is present.
     *              May be {@code null}.
     * @return the value, if present, otherwise {@code other}
     */
    public T orElse(T other) {
        return result != null ? result : other;
    }

    /**
     * If a value is present, returns the value, otherwise returns the result
     * produced by the supplying function.
     *
     * @param supplier the supplying function that produces a value to be returned
     * @return the value, if present, otherwise the result produced by the
     * supplying function
     * @throws NullPointerException if no value is present and the supplying
     *                              function is {@code null}
     */
    public T orElseGet(Supplier<? extends T> supplier) {
        return result != null ? result : supplier.get();
    }

    /**
     * If a value is present, returns the value, otherwise throws
     * {@code NoSuchElementException}.
     *
     * @return the non-{@code null} value described by this {@code Optional}
     * @throws NoSuchElementException if no value is present
     * @since 10
     */
    public T orElseThrow() {
        if (result == null) {
            throw new NoSuchElementException("No value present");
        }
        return result;
    }

    /**
     * If a value is present, returns the value, otherwise throws an exception
     * produced by the exception supplying function.
     *
     * @param <X>               Type of the exception to be thrown
     * @param exceptionSupplier the supplying function that produces an
     *                          exception to be thrown
     * @return the value, if present
     * @throws X                    if no value is present
     * @throws NullPointerException if no value is present and the exception
     *                              supplying function is {@code null}
     * @apiNote A method reference to the exception constructor with an empty argument
     * list can be used as the supplier. For example,
     * {@code IllegalStateException::new}
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (result != null) {
            return result;
        } else {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 存在
     *
     * @return boolean
     */
    public boolean isPresent() {
        return result != null;
    }

    /**
     * 是空
     *
     * @return boolean
     */
    public boolean isEmpty() {
        return result == null;
    }


}
